package com.imcreator.icchat;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.LockSupport;

import org.jline.reader.Completer;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.impl.completer.ArgumentCompleter;
import org.jline.reader.impl.completer.NullCompleter;
import org.jline.reader.impl.completer.StringsCompleter;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;

import com.imcreator.icchat.ClientThreads.ReceiveThread;
import com.imcreator.icchat.Completer.DynamicCompleter;
import com.imcreator.icchat.Objects.Client;
import com.imcreator.icchat.Objects.Server;
import com.imcreator.icchat.ServerThreads.AcceptThread;
import com.imcreator.icchat.ServerThreads.ClientThread;

import cn.hutool.json.JSONUtil;

public class IcChat {
    
    public static Map<String, Object> configMap = new HashMap<>();
    public static Server server = null;
    public static Map<String, Client> clientsMap = new HashMap<>();
    public static Integer port = 8888;
    public static String password = "";
    public static Boolean serverRunning = false;
    public static Boolean isConnecting = false;
    public static Boolean isPasswording = false;
    public static Boolean isExit = false;
    public static Terminal terminal = null;
    public static LineReader lineReader = null;
    public static AcceptThread acceptThread = null;
    public static List<ClientThread> verifingList = new ArrayList<>();
    public static List<String> onlinelist = new ArrayList<>();
    public static DynamicCompleter dynamicCompleter = new DynamicCompleter();

    public static void main(String[] args) {
        // 启动部分
        try {
            terminal = TerminalBuilder.builder().system(true).build();
        } catch (IOException e) {
            System.err.println("程序启动失败！");
            e.printStackTrace();
        }

        Methods.showTitle();
        Methods.checkFile();
        Methods.reloadConfig();
        if (isExit) return;
        Methods.printAbove(Methods.changeColor(
            "程序启动成功，输入/help获取命令帮助", 
            Colors.GREEN_BOLD));

        try {
            // 命令补全
            Completer cmdCompleter = new StringsCompleter("/help", "/exit", "/connect", "/rename", "/start", "/port",
                    "/password", "/disconnect", "/kick", "/stop", "/list", "/tell");

            Completer completer = new ArgumentCompleter(
                cmdCompleter, 
                dynamicCompleter, 
                NullCompleter.INSTANCE
                );

            lineReader = LineReaderBuilder.builder().terminal(terminal).completer(completer).build();

            String prompt = configMap.get("user-name") + "> "; // 输入命令提示信息

            while (!isExit) {
                if (isPasswording) { // 密码输入
                    String pwd = lineReader.readLine(Methods.changeColor("请输入连接密码: ", Colors.YELLOW));
                    if (isConnecting) {
                        Methods.sendMessage(
                            server.getSocket(), 
                            "password", 
                            pwd);
                        LockSupport.park();
                        continue;
                    }
                }

                String msg = lineReader.readLine(prompt);
                
                if (msg.length() > 256) { // 长度判断
                    Methods.printAbove(Methods.changeColor(
                        "输入超出长度的限制！", 
                        Colors.RED_BOLD));
                    continue;
                }

                if (msg.isBlank()) { // 空内容处理
                    continue;
                }

                // 判断是否为命令
                if (!msg.startsWith("/")) { // 若非命令
                    if (serverRunning) {
                        Methods.broadcastMessage(
                            "<" + Methods.changeColor("Server", Colors.PURPLE_BOLD) + "> " + msg,
                             null);
                    } else {
                        if (isConnecting) { // 判断是否已经连接到服务器
                            // 发送信息
                            Methods.sendMessage(server.getSocket(), "message", msg);
                        } else {
                            Methods.printAbove(Methods.changeColor(
                                "请先连接到服务器再尝试发送消息", 
                                Colors.YELLOW_BOLD));
                        }
                    }
                    continue;
                }
                String cmd = msg.replace("/", ""); // 去除命令标识
                String[] str = cmd.split(" "); // 命令分割
                if (cmd.startsWith(" ") || Methods.hasSpaces(cmd)) {
                    Methods.printAbove(Methods.changeColor(
                        "请不要输入额外的空格！", 
                        Colors.RED_BOLD));
                    continue;
                }

                // 执行命令
                if (str.length == 1) {
                    switch (str[0]) {
                        case "help":
                            Methods.printAbove(getHelp());
                            break;
                        case "exit":
                            isExit = true;
                            break;
                        case "start":
                            if (isConnecting) {
                                Methods.printAbove(Methods.changeColor(
                                    "请先断开当前的连接！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            if (serverRunning) {
                                Methods.printAbove(Methods.changeColor(
                                    "服务端已在运行！", 
                                    Colors.RED_BOLD));
                            } else {
                                Methods.start();
                            }
                            break;
                        case "disconnect":
                            if (isConnecting) {
                                Methods.sendMessage(server.getSocket(), "require", "disconnect");
                            } else {
                                Methods.printAbove(Methods.changeColor(
                                    "当前没有连接的服务器", 
                                    Colors.YELLOW_BOLD));
                            }
                            break;
                        case "stop":
                            if (serverRunning) {
                                Methods.stop();
                            } else {
                                Methods.printAbove(Methods.changeColor(
                                    "服务端当前未在运行", 
                                    Colors.YELLOW_BOLD));
                            }
                            break;
                        case "list":
                            if (serverRunning) {
                                Methods.printAbove(Methods.onlineClientsToStringList(clientsMap));
                            } else if (isConnecting) {
                                Methods.printAbove(Methods.onlineClientsToStringList(onlinelist));
                            } else {
                                Methods.printAbove(Methods.changeColor(
                                    "请先开启服务端或连接服务器", 
                                    Colors.YELLOW_BOLD));
                            }
                            break;
                        case "password":
                            if (isConnecting) {
                                Methods.printAbove(Methods.changeColor(
                                    "请先断开当前的连接！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            if (serverRunning) {
                                Methods.printAbove(Methods.changeColor(
                                    "请关闭服务端后再试！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            password = "";
                            Methods.printAbove(Methods.changeColor(
                                "密码已重置", 
                                Colors.YELLOW_BOLD));
                            break;
                        default:
                            Methods.printAbove(Methods.changeColor(
                                "输入不合法！请输入/help查看帮助文档", 
                                Colors.RED_BOLD));
                            break;
                    }
                } else if (str.length == 2) {
                    switch (str[0]) {
                        case "rename":
                            if (isConnecting) {
                                Methods.printAbove(Methods.changeColor(
                                    "请先断开当前的连接！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            String name = str[1];
                            if (Methods.checkName(name)) {
                                configMap.replace("user-name", name);
                                prompt = name + "> "; // 重新赋值
                                Methods.saveConfig();
                            } else {
                                Methods.printAbove(Methods.changeColor(
                                    "昵称只能由中文、英文、数字和下划线组成，且最多16个字符", 
                                    Colors.RED_BOLD));
                            }
                            break;
                        case "connect":
                            if (isConnecting) {
                                Methods.printAbove(Methods.changeColor(
                                    "请先断开当前的连接！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            String[] s = str[1].split(":");
                            Socket socket = null;
                            if (Methods.checkPort(s[1])) {
                                socket = Methods.connect(s[0], s[1]);
                                if (socket != null) {
                                    isConnecting = true;
                                    Thread thread = new ReceiveThread(socket, Thread.currentThread());
                                    thread.start(); // 开启信息监听线程
                                    isConnecting = Methods.sendMessage(
                                        socket, "user-name", 
                                        String.valueOf(IcChat.configMap.get("user-name"))
                                        ); // 向服务端发送用户名
                                    if (!isConnecting) {
                                        socket.close();
                                        continue;
                                    }
                                    server = new Server(socket, thread);
                                    LockSupport.park();
                                }
                            }
                            break;
                        case "port":
                            if (isConnecting) {
                                Methods.printAbove(Methods.changeColor(
                                    "请先断开当前的连接！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            if (serverRunning) {
                                Methods.printAbove(Methods.changeColor(
                                    "请关闭服务端后再试！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            if (Methods.checkPort(str[1])) {
                                port = Integer.parseInt(str[1]);
                                Methods.printAbove("已设置端口号: " + port);
                            }
                            break;
                        case "password":
                            if (isConnecting) {
                                Methods.printAbove(Methods.changeColor(
                                    "请先断开当前的连接！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            if (serverRunning) {
                                Methods.printAbove(Methods.changeColor(
                                    "请关闭服务端后再试！", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            password = str[1];
                            Methods.printAbove(Methods.changeColor(
                                "已设置密码: " + password, 
                                Colors.YELLOW_BOLD));
                            break;
                        case "kick":
                            if (!serverRunning) {
                                Methods.printAbove(Methods.changeColor(
                                    "服务端未在运行", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            
                            String clientName = str[1];
                            if (!clientsMap.keySet().contains(clientName)) {
                                Methods.printAbove(Methods.changeColor(
                                    "该客户端不存在", 
                                    Colors.RED_BOLD));
                                continue;
                            }
                            InetAddress address = IcChat.clientsMap.get(clientName).getSocket().getInetAddress();
                            Methods.kickClient(clientName, null); //断开连接！！！
                            Methods.printAbove(Methods.changeColor(
                                "已将" + clientName + "客户端(" + address + ")踢出服务器", 
                                Colors.YELLOW_BOLD));
                            break;
                        default:
                            Methods.printAbove(Methods.changeColor(
                                "输入不合法！请输入/help查看帮助文档", 
                                Colors.RED_BOLD));
                            break;
                    }
                } else if (str.length == 3) {
                    switch (str[0]) {
                        case "tell":
                            HashMap<String, String> messageMap = new HashMap<>();
                            messageMap.put("type", "tell");
                            messageMap.put("content", str[2]);
                            messageMap.put("to", str[1]);
                            Methods.sendMessage(server.getSocket(), JSONUtil.toJsonStr(messageMap));
                            break;
                        default:
                            Methods.printAbove(Methods.changeColor(
                                "输入不合法！请输入/help查看帮助文档", 
                                Colors.RED_BOLD));
                            break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(0);
    }

    private static String getHelp() {
        return """
                ====================帮助====================
                 注：输入命令时请在开头加“/”

                 /help  -显示此页
                 /exit  -退出程序
                 /list  -列出全部在线客户端

                 /connect [服务器地址:端口号]  -连接至服务器
                 /disconnect  -断开与当前服务器的连接
                 /rename [用户名]  -修改用户名(默认IC-Vistor)
                 /tell [用户名] [内容]  -向某用户发送私信

                 /start  -开启服务端
                 /port [端口号]  -设置服务端监听端口(默认8888)
                 /password [密码]  -设置服务端连接密码(默认无)
                 /kick [用户名]  -将某用户提出
                 /stop  -关闭服务端
                ============================================""";
    }
}
